package com.ndood.gateway.domain.receive.v1.service;

import java.util.SortedMap;

import org.apache.http.util.Asserts;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.response.AlipayTradePayResponse;
import com.alipay.api.response.AlipayTradePrecreateResponse;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson;
import com.ndood.api.app.properties.ApiProperties;
import com.ndood.api.app.sdk.alipay.f2f.model.builder.AlipayTradePayRequestBuilder;
import com.ndood.api.app.sdk.alipay.f2f.model.builder.AlipayTradePrecreateRequestBuilder;
import com.ndood.api.app.sdk.alipay.f2f.model.result.AlipayF2FPayResult;
import com.ndood.api.app.sdk.alipay.f2f.model.result.AlipayF2FPrecreateResult;
import com.ndood.api.app.sdk.alipay.f2f.service.AlipayTradeService;
import com.ndood.api.app.sdk.alipay.f2f.utils.AlipayBuilderUtils;
import com.ndood.api.app.tools.IdUtils;
import com.ndood.api.base.constaints.ApiCode;
import com.ndood.api.base.exception.ApiException;
import com.ndood.api.domain.record.receive.v1.entity.dto.RecoRecOfflineOrderDto;
import com.ndood.api.domain.record.receive.v1.service.RecoRecPlatformOfflineOfficialAlif2fService;
import com.ndood.api.domain.support.merchant.entity.dto.SupportMchRecChannelDto;
import com.ndood.api.domain.support.merchant.entity.dto.SupportMchRecConfigDto;
import com.ndood.api.domain.support.merchant.service.SupportMchRecConfigService;
import com.ndood.api.domain.support.staff.entity.dto.SupportStaffDto;
import com.ndood.common.base.constaints.CommonConstaints;
import com.ndood.gateway.app.rabbitmq.PollingSender;
import com.ndood.gateway.app.websocket.WebSocketServer;
import com.ndood.gateway.base.utils.HttpUtil;

import lombok.extern.slf4j.Slf4j;

/**
 * 收款能力-平台收款-官方支付宝当面付 服务类
 */
@Service
@Slf4j
public class RecPlatformOfflineOfficialAlif2fService {
	
	@Autowired
	private ApiProperties apiProperties;
	
	@Autowired
	private IdUtils idUtils;
	
	@Autowired
	private RecoRecPlatformOfflineOfficialAlif2fService recoRecPlatformOfficialAlif2fService;

	@Autowired
	private SupportMchRecConfigService supportMchRecConfigService;
	
	@Autowired
	private ObjectMapper objectMapper;
	
    @Autowired
    private PollingSender pollingSender;
	
	/**
	 * 1 创建预支付订单 https://docs.open.alipay.com/api_1/alipay.trade.precreate
	 */
	public RecoRecOfflineOrderDto preCreate(String amount, String payRemark, String deviceNo, String ip, 
			SupportStaffDto staff, SupportMchRecChannelDto channel) throws ApiException {
		
		// Step1: 调用支付宝预支付接口
		String orderNo = idUtils.getNextId();
		String payOrderNo = idUtils.getNextId();
		String subject = "官方支付宝扫码支付";
		Assert.notNull(staff.getShopId(), "收银门店号为空!");
		String storeId = String.valueOf(staff.getShopId());
		String expireTime = "5m";
		String notifyUrl = new StringBuilder().append(apiProperties.getDomain()).append("/receive/v1/platform/offline/alif2f/notify/")
				.append(channel.getChannelNo()).append("/").append(channel.getContractType()).append("/").append(staff.getMchId()).toString();
		
		// Step2 处理直清支付
		if(CommonConstaints.CONTRACT_TYPE_DIRECT.equals(channel.getContractType())){
			
			// 1 获取直清商户支付配置
			SupportMchRecConfigDto config = supportMchRecConfigService.getMerchantReceiveConfig(staff.getMchId());
			Asserts.notNull(config, "商户直清收款配置不存在!");
			AlipayTradeService tradeService = AlipayBuilderUtils.buildAlipayTradeService(apiProperties.getPay().getAlipayGateway(), 
					config.getAliAlipayPublicRsa2Secret(), config.getAliAppId(), config.getAliMchPrivateRsa2Secret());
			
			// 2 组装支付请求
			AlipayTradePrecreateRequestBuilder builder = new AlipayTradePrecreateRequestBuilder()
					.setOutTradeNo(payOrderNo)
					.setTotalAmount(amount)
					.setSubject(subject)
					.setOperatorId(String.valueOf(staff.getId()))
					.setStoreId(storeId)
					.setTimeoutExpress(expireTime)
					.setNotifyUrl(notifyUrl);
			AlipayF2FPrecreateResult result = tradeService.tradePrecreate(builder);
			log.info(new Gson().toJson(result));
			
			AlipayTradePrecreateResponse response = result.getResponse();
			// 3: 处理订单
			switch (result.getTradeStatus()) {
			case SUCCESS:
				RecoRecOfflineOrderDto successRecord = recoRecPlatformOfficialAlif2fService.preCreateSuccess(orderNo, payOrderNo, 
						subject, storeId, expireTime, notifyUrl, amount, payRemark, deviceNo, ip, staff, channel, response);
				return successRecord;
				
			case FAILED:
			case UNKNOWN:
			default:
				RecoRecOfflineOrderDto failedRecord = recoRecPlatformOfficialAlif2fService.preCreateFail(orderNo, payOrderNo,
						subject, storeId, expireTime, notifyUrl, amount, payRemark, deviceNo, ip, staff, channel, response);
				return failedRecord;
			}
		}
		
		// Step3: 处理二清支付
		if(CommonConstaints.CONTRACT_TYPE_SECOND.equals(channel.getContractType())) {
			// 1 组装支付请求
			AlipayTradeService tradeService = AlipayBuilderUtils.buildAlipayTradeService(apiProperties.getPay().getAlipayGateway(), 
					apiProperties.getPay().getAlipayRsa2PublicSecret(), apiProperties.getPay().getAlipayAppId(), apiProperties.getPay().getAlipayMchRsa2PrivateSecret());
			
			AlipayTradePrecreateRequestBuilder builder = new AlipayTradePrecreateRequestBuilder()
					.setOutTradeNo(payOrderNo)
					.setTotalAmount(amount)
					.setSubject(subject)
					.setOperatorId(String.valueOf(staff.getId()))
					.setStoreId(storeId)
					.setTimeoutExpress(expireTime)
					.setNotifyUrl(notifyUrl);
			AlipayF2FPrecreateResult result = tradeService.tradePrecreate(builder);
			log.info(new Gson().toJson(result));
			AlipayTradePrecreateResponse response = result.getResponse();
			
			// 2: 处理订单
			switch (result.getTradeStatus()) {
			case SUCCESS:
				RecoRecOfflineOrderDto successRecord = recoRecPlatformOfficialAlif2fService.preCreateSuccess(orderNo, payOrderNo,
						subject, storeId, expireTime, notifyUrl, amount, payRemark, deviceNo, ip, staff, channel, response);
				return successRecord;
				
			case FAILED:
			case UNKNOWN:
			default:
				RecoRecOfflineOrderDto failedRecord = recoRecPlatformOfficialAlif2fService.preCreateFail(orderNo, payOrderNo,
						subject, storeId, expireTime, notifyUrl, amount, payRemark, deviceNo, ip, staff, channel, response);
				return failedRecord;
			}
		}
		
		throw new ApiException(ApiCode.ERR_SERVER, "不支持的合同清算类型");
		
	}

	/**
	 * 2 处理订单通知
	 */
	public void preCreateNotify(String channelNo, Integer contractType, Integer merchantId, SortedMap<String, Object> params) throws Exception {
		// Step1: 获取参数
		String sign = (String) params.get("sign");
		String signType = (String) params.get("sign_type");
		String charset = (String) params.get("charset");
		String content = HttpUtil.getSignContent(params);

		// Step2: 验证签名
		boolean signOk = false;
		if(CommonConstaints.CONTRACT_TYPE_DIRECT.equals(contractType)) {
			SupportMchRecConfigDto config = supportMchRecConfigService.getMerchantReceiveConfig(merchantId);
			Asserts.notNull(config, "商户直清收款配置不存在!");
			signOk = AlipaySignature.rsaCheck(content, sign, config.getAliAlipayPublicRsa2Secret(), charset, signType);
			
		}else if(CommonConstaints.CONTRACT_TYPE_SECOND.equals(contractType)) {
			signOk = AlipaySignature.rsaCheck(content, sign, apiProperties.getPay().getAlipayRsa2PublicSecret(), charset, signType);
		}else {
			throw new ApiException(ApiCode.ERR_SERVER, "不支持的合同清算类型");
		}
		if(!signOk) {
			throw new ApiException(ApiCode.ERR_SERVER, "支付宝验签失败");
		}
		
		// Step3: 记账
		RecoRecOfflineOrderDto order = recoRecPlatformOfficialAlif2fService.preCreateNotify(channelNo, contractType, merchantId, params);
		
		// Step4: 反向ajax通知前端支付结果
		if(order==null) {
			return;
		}
		WebSocketServer.sendInfo(objectMapper.writeValueAsString(order), order.getOrderNo());
	}

	/**
	 * 3 处理条形码支付 https://docs.open.alipay.com/api_1/alipay.trade.pay
	 */
	public RecoRecOfflineOrderDto barCode(String amount, String barCode, String payRemark, String deviceNo, String ip,
			SupportStaffDto staff, SupportMchRecChannelDto channel) throws ApiException {
		// Step1: 调用支付宝预支付接口
		String orderNo = idUtils.getNextId();
		String payOrderNo = idUtils.getNextId();
		String subject = "官方支付宝被扫支付";
		Assert.notNull(staff.getShopId(), "收银门店号为空!");
		String storeId = String.valueOf(staff.getShopId());
		String expireTime = "5m";
		
		// Step2 处理直清支付
		if(CommonConstaints.CONTRACT_TYPE_DIRECT.equals(channel.getContractType())){
			
			// 1 获取直清商户支付配置
			SupportMchRecConfigDto config = supportMchRecConfigService.getMerchantReceiveConfig(staff.getMchId());
			Asserts.notNull(config, "商户直清收款配置不存在!");
			AlipayTradeService tradeService = AlipayBuilderUtils.buildAlipayTradeService(apiProperties.getPay().getAlipayGateway(), 
					config.getAliAlipayPublicRsa2Secret(), config.getAliAppId(), config.getAliMchPrivateRsa2Secret());
			
			// 2 组装支付请求
			AlipayTradePayRequestBuilder builder = new AlipayTradePayRequestBuilder()
					.setOutTradeNo(payOrderNo)
					.setAuthCode(barCode)
					.setTotalAmount(amount)
					.setSubject(subject)
					.setOperatorId(String.valueOf(staff.getId()))
					.setStoreId(storeId)
					.setTimeoutExpress(expireTime);
			AlipayF2FPayResult result = tradeService.tradePay(builder);
			log.info(new Gson().toJson(result));
			
			AlipayTradePayResponse response = result.getResponse();
			// 3: 处理订单
			switch (result.getTradeStatus()) {
			case SUCCESS:
				RecoRecOfflineOrderDto successRecord = recoRecPlatformOfficialAlif2fService.barCodeSuccess(barCode, orderNo, payOrderNo, 
						subject, storeId, expireTime, amount, payRemark, deviceNo, ip, staff, channel, response);
				return successRecord;
				
			case PAYING:
				RecoRecOfflineOrderDto payingRecord = recoRecPlatformOfficialAlif2fService.barCodePaying(barCode, orderNo, payOrderNo,
						subject, storeId, expireTime, amount, payRemark, deviceNo, ip, staff, channel, response);
				
				// 通知mq轮询队列进行轮询
				pollingSender.send(payOrderNo);
				return payingRecord;
				
			case FAILED:
			case UNKNOWN:
			default:
				RecoRecOfflineOrderDto failedRecord = recoRecPlatformOfficialAlif2fService.barCodeFail(barCode, orderNo, payOrderNo,
						subject, storeId, expireTime, amount, payRemark, deviceNo, ip, staff, channel, response);
				return failedRecord;
			}
		}
		
		// Step3: 处理二清支付
		if(CommonConstaints.CONTRACT_TYPE_SECOND.equals(channel.getContractType())) {
			// 1 组装支付请求
			AlipayTradeService tradeService = AlipayBuilderUtils.buildAlipayTradeService(apiProperties.getPay().getAlipayGateway(), 
					apiProperties.getPay().getAlipayRsa2PublicSecret(), apiProperties.getPay().getAlipayAppId(), apiProperties.getPay().getAlipayMchRsa2PrivateSecret());
			
			// 2 组装支付请求
			AlipayTradePayRequestBuilder builder = new AlipayTradePayRequestBuilder()
					.setOutTradeNo(payOrderNo)
					.setAuthCode(barCode)
					.setTotalAmount(amount)
					.setSubject(subject)
					.setOperatorId(String.valueOf(staff.getId()))
					.setStoreId(storeId)
					.setTimeoutExpress(expireTime);
			AlipayF2FPayResult result = tradeService.tradePay(builder);
			log.info(new Gson().toJson(result));
			
			AlipayTradePayResponse response = result.getResponse();
			// 3: 处理订单
			switch (result.getTradeStatus()) {
			case SUCCESS:
				RecoRecOfflineOrderDto successRecord = recoRecPlatformOfficialAlif2fService.barCodeSuccess(barCode, orderNo, payOrderNo, 
						subject, storeId, expireTime, amount, payRemark, deviceNo, ip, staff, channel, response);
				return successRecord;
				
			case PAYING:
				RecoRecOfflineOrderDto payingRecord = recoRecPlatformOfficialAlif2fService.barCodePaying(barCode, orderNo, payOrderNo,
						subject, storeId, expireTime, amount, payRemark, deviceNo, ip, staff, channel, response);
				return payingRecord;
				
			case FAILED:
			case UNKNOWN:
			default:
				RecoRecOfflineOrderDto failedRecord = recoRecPlatformOfficialAlif2fService.barCodeFail(barCode, orderNo, payOrderNo,
						subject, storeId, expireTime, amount, payRemark, deviceNo, ip, staff, channel, response);
				return failedRecord;
			}
		}
		
		throw new ApiException(ApiCode.ERR_SERVER, "不支持的合同清算类型");
	}

}
